外观
TDD 测试驱动开发
使用 Claude 进行 TDD(测试驱动开发)需要明确的提示词。Claude 天然会先写实现,再写测试。TDD(测试驱动开发)要求相反的顺序。
目录
- TL;DR
- 问题所在
- 配置
- 红-绿-重构循环
- 与 Claude Code 功能集成
- 反模式
- 进阶模式
- 延伸阅读
TL;DR
Plain
红 → 绿 → 重构
但你必须明确提示 Claude:
"为 [功能] 编写一个失败的测试。暂不编写实现。"问题所在
没有明确指令时,Claude 会:
- 编写实现代码
- 然后编写能通过该实现的测试
这违背了 TDD(测试驱动开发)的目的:测试应该驱动设计,而非验证已有代码。
配置
CLAUDE.md 配置
添加到你的项目 CLAUDE.md:
Markdown
## 测试约定
### TDD(测试驱动开发)工作流
- 始终在实现前编写失败的测试
- 使用 AAA 模式:Arrange(准备)-Act(执行)-Assert(断言)
- 每个测试尽量只有一个断言
- 测试名称描述行为:"should_return_empty_when_no_items"
### 测试优先规则
- 当我要求实现功能时,先写测试
- 测试最初应该失败(无实现存在)
- 只有在测试编写完成后,才实现让测试通过的最少代码自动运行测试的钩子(可选)
创建 .claude/hooks/test-on-save.sh:
Bash
#!/bin/bash
# 测试文件变更时自动运行测试
if [[ "$1" == *test* ]] || [[ "$1" == *spec* ]]; then
npm test --watchAll=false 2>&1 | head -20
fi红-绿-重构循环
第一阶段:红(编写失败的测试)
提示词:
Plain
为 [功能描述] 编写一个失败的测试。
暂不编写实现。
测试应该失败,因为函数/方法不存在。示例:
Plain
为一个计算购物车商品总价的函数编写失败的测试,
如果总价超过 100 元则应用 10% 折扣。
暂不实现该函数。预期 Claude 行为:
- 创建包含测试用例的测试文件
- 测试引用不存在的函数
- 运行测试会失败,提示「函数未定义」或类似错误
验证:
Bash
npm test # 应该失败,提示「calculateCartTotal is not defined」第二阶段:绿(最小实现)
提示词:
Plain
现在实现让这些测试通过的最少代码。
只写足够通过当前测试的代码,不要多。预期 Claude 行为:
- 创建实现文件
- 编写满足测试的最少代码
- 避免过度工程化
验证:
Bash
npm test # 应该通过第三阶段:重构(清理代码)
提示词:
Plain
重构实现以提升代码质量。
重构后测试必须保持绿色。
重点关注:[可读性 / 性能 / 消除重复]预期 Claude 行为:
- 在不改变行为的前提下改善代码
- 运行测试验证仍能通过
- 记录任何重大变更
与 Claude Code 功能集成
配合 TodoWrite
在任务列表中追踪 TDD(测试驱动开发)阶段:
Plain
用户:「使用 TDD(测试驱动开发)实现用户认证」
Claude 创建待办事项:
- [ ] 红:为登录编写失败的测试
- [ ] 绿:实现登录以通过测试
- [ ] 重构:清理登录实现
- [ ] 红:为登出编写失败的测试
- [ ] 绿:实现登出
- [ ] 重构:清理配合计划模式
使用计划模式规划测试策略:
Plain
[按 Shift+Tab 进入计划模式]
我需要用 TDD(测试驱动开发)实现一个购物车。
在我们开始写任何代码之前,先规划测试用例。Claude 会以只读方式探索代码库,然后在任何实现之前提出测试计划。
配合 Hooks(钩子)
使用工具后钩子在编辑后自动运行测试:
JSON
// 在 .claude/settings.json 中
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"command": "npm test --watchAll=false 2>&1 | head -20"
}
]
}
}配合子智能体
将测试编写委托给专注范围的智能体:
Plain
使用 test-writer 智能体为 UserService 类创建全面的测试,
覆盖所有边缘情况。
然后我会按照这些测试来实现。反模式
验证缺口
验证缺口是智能体在验证套件确认之前就报告功能完成的失败模式。这是多会话智能体工作中最常见的可靠性故障,完全可以通过正确的框架设计来预防。
三个可观察症状:智能体在任何测试命令运行之前就打印成功消息;测试运行但 stderr 被丢弃或未读取;仅单元测试通过,而验收标准规定了端到端行为。
修复方案是一个三层验证栈,在功能被标记为 passing 之前必须全部通过:
- 代码检查 — 语法和风格检查(最快,在运行测试前捕获明显错误)
- 单元测试和集成测试 — 各组件的功能正确性
- 端到端测试 — 用户或外部调用者所见的行为契约
每一层捕获不同类别的故障。单元测试可以通过,而组件边界会断裂。端到端测试能发现单元测试看不到的状态传播错误和生命周期问题。跳过任何一层都会留下缺口。
独立评估者原则:编写代码的智能体不能是同一个调用来认证其完成。这不是对模型的不信任;而是关于上下文如何影响评估。一个刚花了两个小时构建功能的智能体会对模糊输出作出慈善解释。一个独立读取退出代码的工具后钩子或第二个智能体则不会。examples/hooks/bash/verification-gate.sh 中的钩子实现了这个模式。
Anthropic 在其框架设计研究中记录了这个故障:在裸运行(无框架)中,他们的智能体在 20 分钟后报告游戏编辑器完成。什么都不工作。向框架添加独立评估者后,同一模型运行了 6 小时并交付了可用结果。(来源:https://www.anthropic.com/engineering/harness-design-long-running-apps)
WIP=1 规则与此相关:每次只保持一个功能处于 active 状态,意味着验证缺口发生时,只影响一个功能,而非同时影响多个。
不该做的事
| 反模式 | 错误原因 | 正确做法 |
|---|---|---|
| 「为这个功能写测试」 | Claude 会先实现 | 「写尚不存在的失败测试」 |
| 「添加测试和实现」 | 失去测试优先的好处 | 分成两个提示词 |
| 「确保测试通过」 | 鼓励先实现 | 「写测试,然后最小化实现」 |
| 跳过重构阶段 | 积累技术债务 | 绿色后始终重构 |
| 同时处理多个功能 | 失去专注 | 每个 TDD(测试驱动开发)循环一个功能 |
常见错误
错误:要求 Claude「测试」现有代码。
Plain
# 错误
「为现有的 calculateTotal 函数写测试」
# 正确
「假设函数不存在,为 calculateTotal 的行为写测试。
然后我们验证现有实现是否通过。」错误:合并红色和绿色阶段。
Plain
# 错误
「带测试实现 calculateTotal」
# 正确
「为 calculateTotal 写失败的测试。到此为止。」
[测试写完后]
「现在实现以通过这些测试。」进阶模式
基于属性的测试
Plain
为排序函数编写基于属性的测试。
需要测试的属性:
- 输出长度等于输入长度
- 所有输入元素都存在于输出中
- 输出是有序的
使用 fast-check 或类似库。变异测试
Plain
测试通过后,运行变异测试来发现薄弱点。
识别无法捕获变异的测试。更进一步:JiTTesting 在 PR 时自动应用变异测试——由 LLM 生成,短暂存在,零维护。Meta 大规模部署了这项技术,与传统测试相比回归捕获率提升了 4 倍。参见 Meta 的即时捕获测试生成和「方法论指南」,了解当今 Claude Code 的近似模式。
遗留代码的 TDD(测试驱动开发)
Plain
我需要重构 legacyFunction。
首先,编写记录当前行为的特征测试。
然后我们可以有信心地重构。示例会话
用户请求
Plain
使用 TDD(测试驱动开发)实现一个 URL 缩短服务。第一阶段:红
Plain
让我们使用 TDD(测试驱动开发)。首先,为以下情况编写失败的测试:
1. 缩短 URL 返回一个短代码
2. 检索短代码返回原始 URL
3. 无效 URL 被拒绝
4. 过期链接返回错误
暂不实现任何内容。第二阶段:绿
Plain
测试已编写且失败。现在实现让它们通过的最少代码。
暂时使用内存存储。第三阶段:重构
Plain
测试已通过。现在重构:
- 将 URL 验证提取到独立函数
- 添加合适的错误类型
- 改善变量名
每次修改后运行测试以确保保持绿色。延伸阅读
- 「../core/methodologies.md」 — 完整方法论参考
- 「紧密反馈循环」 — 第 9.5 节
- 「examples/skills/tdd-workflow.md」 — TDD(测试驱动开发)Skills(技能模块)模板
- Anthropic 最佳实践
- 「task-management.md」 — 使用 Tasks API 跨会话追踪 TDD(测试驱动开发)循环
- Superpowers — 将 TDD(测试驱动开发)作为强制门控的插件套件:在失败测试存在之前编写的代码会被删除并从头重做。比手动提示词更严格的执行。
来源:飞书 · AI Spark 知识库 | 原文(最新版):https://lcnniolukk80.feishu.cn/wiki/TSlWwH7koiqK1vk1i2HcKWjpnIh | 归档:2026-06-04